<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>码元</title>
</head>
<body>
    <script>
        /**
         * 码元: 
         *      ucs-2 : 早期,js对字符串的编码规范使用ucs-2, 规范规定,每个文字对应16位的空间, 这个空间称为码元
         *      utf-16: 后来生僻字越来越多, 还有emoji表情, 16位空间不够用,js就把编码规范换成utf16, 
         *         规范规定一个文字可以占用1个码元(16位),也可以2个码元(32位)空间, 这样一来有些特殊文字就占用了2个码元
         *      String.length String[x] slice splice  实际上都是使用码元的数量, 会出问题, 乱码
         * 码点: 
         *      不管占用空间, 一个文字就是一个码点
         * 解决乱码方法:  String.codePointAt(x)   返回字符的Unicode编码, 如果大于65536(16位2进制,或 0xffff 4位16进制), 
         *               说明字符是2个码元,否则是1个码元
         *               String.fromCodePoint(x) 按照码点来恢复文字
         */
        let str = '😏哈哈😈👻'
        console.log(str[0], str[1])  //乱码

        //重写slice方法, 传入码点的起始坐标 pStart, pEnd
        String.prototype.sliceByPoint = function(pStart, pEnd){
            let resoult = ''    //截图的结果
            let pIndex = 0  //码点的指针 
            let cIndex = 0  //码元的指针
            while(1){
                //this : 哪个字符串调用该方法, this就是这个字符串
                if(pIndex >= pEnd || cIndex >= this.length){   
                    break
                }
                const point = this.codePointAt(cIndex)  //计算码元的unicode
                if(pIndex >= pStart){
                    resoult += String.fromCodePoint(point)     //unicode编码转string
                }
                cIndex += point > 0xffff ? 2 : 1 //是否大于16位2进制, 大于就是占用2个码元, 否则就是1个码元. 码元指针移动
                pIndex++
            }
            return resoult
        }
        let str2 = str.sliceByPoint(0,1)
        console.log(str2);
    </script>
</body>
</html>